#pragma once

#include <Windows.h>
#include <math.h>

enum STROKE_STATE {
	STROKE_NONE,
	STROKE_START,
	STROKE_MIDDLE,
	STROKE_END
};

class Document
{
private:
	HBITMAP hBmp;
	HDC bufDC;

	int _width, _height;
	COLORREF _pc;

	STROKE_STATE stroke;
	
	void* pBmpBits;
	//void* pBmpBits2;
	int stride;
	
	int *xmin;
	int *xmax;
	
	int ymin, ymax;

	void ScanEdge( double px1, double py1, double px2, double py2 ) {
		int y1 = py1 + 0.5;
		int y2 = py2 + 0.5;
		int dy = abs( y2-y1 );
		// exclude horizaontal edges
		if( dy== 0 ) return;

		int x1 = px1 + 0.5;
		int x2 = px2 + 0.5;
		double dx = (x2-x1)/(double)dy;
		double x;

		if( y1<y2 ) {
			ymin = min( y1, ymin ), ymax = max( ymax, y2 );
			x = x1;
			
			for( int y=y1; y<y2; y++ ) {
				if( xmin[y] > x )
					xmin[y] = x;
				if( xmax[y] < x )
					xmax[y] = x;
				x+=dx;
			}
		} else {
			ymin = min( ymin, y2 ), ymax = max( y1, ymax );
			dx = -dx;
			x = x2;

			for( int y=y2; y<y1; y++ ) {
				if( xmin[y] > x )
					xmin[y] = x;
				if( xmax[y] < x )
					xmax[y] = x;
				x+=dx;
			}
		}
	
	}

public:
	Document() : stroke( STROKE_NONE ), _pc( 0 ), stride(0) {};
	~Document(void);

	int Create( int width, int height );

	void Render( HDC hdc, int x, int y ) {
		BitBlt( hdc, x, y, _width, _height, bufDC, 0, 0, SRCCOPY);
	}
	void DrawLine( int x1, int y1, int x2, int y2 );
	void DrawLine( int x1, int y1, int x2, int y2, double width1, double width2 );
	void BeginStroke( int x, int y );
	void EndStroke();
	void DiscardLine() { stroke = STROKE_MIDDLE; }

	COLORREF getPenColorRef() { return _pc; }
	void setPenColor( COLORREF c ) { _pc = c; }

	int getWidth() { return _width; }
	int getHeight() { return _height; }

	void PutPixel( int x, int y ) {
		if( x<0 || y<0 || x>=_width || y>=_height )
			return;
		UCHAR *p = (UCHAR*)pBmpBits + (stride * y + (x<<2)/* multi by 4 */);
		*p++ = GetBValue( _pc );
		*p++ = GetGValue( _pc );
		*p = GetRValue( _pc );
	}

	void RenderHLine( int y, int xmin, int xmax ) {
		if( y<0 || y>=_height || xmax<0 || xmin >=_width )
			return;
		xmin = max( 0, xmin );
		xmax = min( _width-1, xmax );
		
		UCHAR *p = (UCHAR*)pBmpBits + (stride * y + (xmin<<2)/* multi by 4 */);
		UCHAR r = GetRValue( _pc );
		UCHAR g = GetGValue( _pc );
		UCHAR b = GetBValue( _pc );
		for( int x=xmin; x<=xmax; x++ ) {
			*p++ = b;
			*p++ = g;
			*p++ = r;
			*p++ = 255; // alpha
		}
	}

	void FloodFill( COLORREF c ) {
		int cnt = _width * _height;
		UCHAR r = GetRValue( c );
		UCHAR g = GetGValue( c );
		UCHAR b = GetBValue( c );
		UCHAR *p = (UCHAR*)pBmpBits;

		while( cnt-- >0 ) {
			*p++ = b;
			*p++ = g;
			*p++ = r;
			*p++ = 255; // alpha
		}

		//DrawLine( 100, 100, 101, 250, 13, 10 );
	}
};

